#include <iostream>
#include <string>
#include <vector>
#include <unistd.h>
#include <assert.h>
#include <ctime>
#include <sys/types.h>
#include <sys/wait.h>

#define PROC_NUM 5
#define MakeSeed() srand((unsigned long)time(nullptr) ^ getpid())

//交给子进程的任务
typedef void(*func_t)();

void IOtask()
{
    std::cout << "pid(" << getpid() << "): " << "IO任务\n" << std::endl;
}

void flushtask()
{
    std::cout << "pid(" << getpid() << "): " << "刷新任务\n" << std::endl;
}

void downloadtask()
{
    std::cout << "pid(" << getpid() << "): " << "下载任务\n" << std::endl;
}

void loadTask(std::vector<func_t>* funcMap)
{
    assert(funcMap);
    funcMap->push_back(IOtask);
    funcMap->push_back(flushtask);
    funcMap->push_back(downloadtask);
}

class subEp
{
public:
    subEp(pid_t id,int writeFd)
        :_subId(id),_writeFd(writeFd)
        {
            char buffer[1024];
            snprintf(buffer,sizeof buffer ,"process%d-[pid(%d)-writeFd(%d)]",num,_subId,_writeFd);
            _name = buffer;
        }
    std::string getName() const
    {
        return _name;
    }
    pid_t getSubId() const
    {
        return _subId;
    }
    int getWriteFd() const
    {
        return _writeFd;
    }
private:
    static int num;
    std::string _name;
    pid_t _subId;
    int _writeFd;
};

int subEp::num = 0;

int recvTask(int fd)
{
    int code = 0;
    ssize_t s = read(fd,&code,sizeof(code));
    if(s == 4)return code;
    else return -1;
    
}

void createSubprocess(std::vector<subEp>* subs,const std::vector<func_t>& funcMap)
{
    std::vector<int> deleteFd;
    for(int i = 0;i < PROC_NUM;i++)
    {
        int fds[2];
        int n = pipe(fds);
        assert(n == 0);
        (void)n;
        pid_t id = fork();
        assert(id != -1);

        if(id == 0)
        {
            //因为依次创建子进程，会继承父进程的读端
            for(int i = 0;i < deleteFd.size();i++)close(deleteFd[i]);
            
            close(fds[1]);
            int taskNum = funcMap.size();
            while(true)
            {
                int commandcode = recvTask(fds[0]);
                if(commandcode >= 0 && commandcode < taskNum)
                {
                    funcMap[commandcode]();
                }
                else if(commandcode == -1)break;
            }
            close(fds[0]);
            exit(0);
        }

        close(fds[0]);
        subEp sub(id,fds[1]);
        subs->push_back(sub);
        deleteFd.push_back(fds[1]);
    }
}

void sendTask(const subEp& process,int taskNum)
{
    std::cout << "send task num: " << taskNum << " send to ->" << process.getName() << std::endl;
    int n = write(process.getWriteFd(),&taskNum,sizeof(int));
    assert(n == 4);
    (void)n;
}

void loadBalanceContrl(const std::vector<subEp> &subs,const std::vector<func_t> funcMap,int taskCnt)
{
    int subprocNum = subs.size();
    int taskNum = funcMap.size();

    bool forever = (taskCnt == 0)? true : false;
    while(true)
    {
        int subIdx = rand()%subprocNum;
        int taskIdx = rand()%taskNum;

        sendTask(subs[subIdx],taskIdx);
        sleep(1);
        if(!forever)
        {
            taskCnt--;
            if(taskCnt == 0)break;
        }
    }
    for(int i = 0 ;i < subprocNum;i++) close(subs[i].getWriteFd());
    
}

void waitProcess(std::vector<subEp> &processes)
{
    int processnum = processes.size();
    for(int i = 0;i < processnum;i++)
    {
        waitpid(processes[i].getSubId(),nullptr,0);
        std::cout << "wait subprocess success ..." << processes[i].getSubId() << std::endl;
    }
}

int main()
{
    MakeSeed();

    //加载方法表
    std::vector<func_t> funcMap;
    loadTask(&funcMap); 

    //创建子进程，并维护管道
    std::vector<subEp> subs;
    createSubprocess(&subs,funcMap);

    //控制子进程，向子进程发送控制码
    int taskCnt = 4;
    loadBalanceContrl(subs,funcMap,taskCnt);

    //回收子进程
    waitProcess(subs);

    return 0;
}